/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "securec.h"
#include "sle_ssap_client_parcel.h"
#include "sle_hilog.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {
// SsapClientFindStructure
SsapClientFindStructure::SsapClientFindStructure(const ClientFindStructure &param)
{
    type_ = param.findType;
    startHandle_ = param.startHandle;
    endHandle_ = param.endHandle;
    Uuid uuid(param.uuid);
    uuid_ = uuid;
    reserve_ = param.reserve;
}

bool SsapClientFindStructure::Marshalling(Parcel &parcel) const
{
    if(!parcel.WriteUint8(type_)) {
        return false;
    }
    if(!parcel.WriteUint16(startHandle_)) {
        return false;
    }
    if(!parcel.WriteUint16(endHandle_)) {
        return false;
    }
    if (!parcel.WriteParcelable(&uuid_)) {
        return false;
    }
    if(!parcel.WriteUint8(reserve_)) {
        return false;
    }
    return true;
}


SsapClientFindStructure *SsapClientFindStructure::Unmarshalling(Parcel &parcel)
{
    SsapClientFindStructure *param = new SsapClientFindStructure();
    if (param != nullptr && !param->ReadFromParcel(parcel)) {
        delete param;
        param = nullptr;
    }
    return param;
}

bool SsapClientFindStructure::ReadFromParcel(Parcel &parcel)
{
    if (!parcel.ReadUint8(type_)) {
        return false;
    }
    if (!parcel.ReadUint16(startHandle_)) {
        return false;
    }
    if (!parcel.ReadUint16(endHandle_)) {
        return false;
    }
    std::shared_ptr<Uuid> uuid(parcel.ReadParcelable<Uuid>());
    if (!uuid) {
        return false;
    }
    uuid_ = *uuid;
    if (!parcel.ReadUint8(reserve_)) {
        return false;
    }
    return true;
}

void SsapClientFindStructure::ConvertToClientFindStructure(ClientFindStructure &param) const
{
    param.findType = (SsapFindType)type_;
    param.startHandle = startHandle_;
    param.endHandle = endHandle_;
    param.uuid = uuid_.ConvertToSleUuid();
    param.reserve = reserve_;
}

SleErrorCode SsapClientFindStructure::CheckClientFindStructure(const ClientFindStructure &param)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(param.findType >= SSAP_FIND_TYPE_SERVICE_STRUCTURE_TYPE && param.findType <= SSAP_FIND_TYPE_EVENT_TYPE,
        SLE_ERR_INVALID_PARAM, "param client find type error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param.startHandle <= param.endHandle,
        SLE_ERR_INVALID_PARAM, "param client start handle than end handle error!");
    SleErrorCode ret = Uuid::CheckSleUuid(param.uuid);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM, "param client uuid error!");
    return SLE_NO_ERROR;
}

// SsapClientReadReqByUUID
SsapClientReadReqByUUID::SsapClientReadReqByUUID(const ClientReadReqByUUID &param)
{
    type_ = param.findType;
    startHandle_ = param.startHandle;
    endHandle_ = param.endHandle;
    Uuid uuid(param.uuid);
    uuid_ = uuid;
}

bool SsapClientReadReqByUUID::Marshalling(Parcel &parcel) const
{
    if(!parcel.WriteUint8(type_)) {
        return false;
    }
    if(!parcel.WriteUint16(startHandle_)) {
        return false;
    }
    if(!parcel.WriteUint16(endHandle_)) {
        return false;
    }
    if (!parcel.WriteParcelable(&uuid_)) {
        return false;
    }
    return true;
}

SsapClientReadReqByUUID *SsapClientReadReqByUUID::Unmarshalling(Parcel &parcel)
{
    SsapClientReadReqByUUID *param = new SsapClientReadReqByUUID();
    if (param != nullptr && !param->ReadFromParcel(parcel)) {
        delete param;
        param = nullptr;
    }
    return param;
}

bool SsapClientReadReqByUUID::ReadFromParcel(Parcel &parcel)
{
    if (!parcel.ReadUint8(type_)) {
        return false;
    }
    if (!parcel.ReadUint16(startHandle_)) {
        return false;
    }
    if (!parcel.ReadUint16(endHandle_)) {
        return false;
    }
    std::shared_ptr<Uuid> uuid(parcel.ReadParcelable<Uuid>());
    if (!uuid) {
        return false;
    }
    uuid_ = *uuid;
    return true;
}

void SsapClientReadReqByUUID::ConvertToClientReadReqByUUID(ClientReadReqByUUID &param) const
{
    param.findType = (SsapFindType)type_;
    param.startHandle = startHandle_;
    param.endHandle = endHandle_;
    param.uuid = uuid_.ConvertToSleUuid();
}

SleErrorCode SsapClientReadReqByUUID::CheckClientReadReqByUUID(const ClientReadReqByUUID &param)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(param.findType >= SSAP_FIND_TYPE_SERVICE_STRUCTURE_TYPE && param.findType <= SSAP_FIND_TYPE_EVENT_TYPE,
        SLE_ERR_INVALID_PARAM, "param client find type error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param.startHandle <= param.endHandle,
        SLE_ERR_INVALID_PARAM, "param client start handle than end handle error!");
    SleErrorCode ret = Uuid::CheckSleUuid(param.uuid);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM, "param client uuid error!");
    return SLE_NO_ERROR;
}

// SsapClientHandleValue
SsapClientHandleValue::SsapClientHandleValue(const ClientHandleValue &value)
{
    handle_ = value.handle;
    type_ = value.type;
    length_ = value.dataLength;
    if (value.data != nullptr && length_ != 0) {
        data_ = std::make_unique<uint8_t[]>(length_);
        (void)memcpy_s(data_.get(), length_, value.data, length_);
    } else {
        data_ = nullptr;
        length_ = 0;
    }
}

SsapClientHandleValue::SsapClientHandleValue(const ClientWriteParam &param)
{
    handle_ = param.handle;
    type_ = param.type;
    length_ = param.dataLength;
    if (param.data != nullptr && length_ != 0) {
        data_ = std::make_unique<uint8_t[]>(length_);
        (void)memcpy_s(data_.get(), length_, param.data, length_);
    } else {
        data_ = nullptr;
        length_ = 0;
    }
}

bool SsapClientHandleValue::Marshalling(Parcel &parcel) const
{
    if(!parcel.WriteUint16(handle_)) {
        return false;
    }
    if(!parcel.WriteUint8(type_)) {
        return false;
    }
    if(!parcel.WriteUint16(length_)) {
        return false;
    }
    for (size_t i = 0; i < length_; i++) {
        if(!parcel.WriteUint8(data_[i])) {
            return false;
        }
    }
    return true;
}

SsapClientHandleValue *SsapClientHandleValue::Unmarshalling(Parcel &parcel)
{
    SsapClientHandleValue *value = new SsapClientHandleValue();
    if (value != nullptr && !value->ReadFromParcel(parcel)) {
        delete value;
        value = nullptr;
    }
    return value;
}

bool SsapClientHandleValue::ReadFromParcel(Parcel &parcel)
{
    if (!parcel.ReadUint16(handle_)) {
        return false;
    }
    if (!parcel.ReadUint8(type_)) {
        return false;
    }
    if (!parcel.ReadUint16(length_)) {
        return false;
    }
    if (length_ != 0) {
        uint8_t data[length_];
        for (size_t i = 0; i < length_; i++) {
            if (!parcel.ReadUint8(data[i])) {
                return false;
            }
        }
        data_ = std::make_unique<uint8_t[]>(length_);
        if (memcpy_s(data_.get(), length_, data, length_) != SLE_NO_ERROR) {
            return false;
        }
    }
    return true;
}

void SsapClientHandleValue::ConvertToClientHandleValue(ClientHandleValue &value) const
{
    value.handle = handle_;
    value.type = (SleSsapPropertyType)type_;
    value.dataLength = length_;
    value.data = data_.get();
}

void SsapClientHandleValue::ConvertToClientWriteParam(ClientWriteParam &param) const
{
    param.handle = handle_;
    param.type = (SleSsapPropertyType)type_;
    param.dataLength = length_;
    param.data = data_.get();
}

SleErrorCode SsapClientHandleValue::CheckClientWriteParam(const ClientWriteParam &param)
{
    SLE_ASSERT_AND_RETURN_RET_LOG((param.type >= SLE_SSAP_PROPERTY_TYPE && param.type <= SLE_SSAP_DESCRIPTOR_TYPE_RFU) ||
        param.type == SLE_SSAP_DESCRIPTOR_TYPE_CUSTOM, SLE_ERR_INVALID_PARAM, "param client write handle error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param.dataLength != 0, SLE_ERR_INVALID_PARAM, "param client write data length 0 error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param.data, SLE_ERR_INVALID_PARAM, "param client write data null error!");
    return SLE_NO_ERROR;
}

// SsapClientFindServiceRes
SsapClientFindServiceRes::SsapClientFindServiceRes(const ClientFindServiceRes &result)
{
    startHandle_ = result.startHandle;
    endHandle_ = result.endHandle;
    Uuid uuid(result.uuid);
    uuid_ = uuid;
}

bool SsapClientFindServiceRes::Marshalling(Parcel &parcel) const
{
    if(!parcel.WriteUint16(startHandle_)) {
        return false;
    }
    if(!parcel.WriteUint16(endHandle_)) {
        return false;
    }
    if (!parcel.WriteParcelable(&uuid_)) {
        return false;
    }
    return true;
}

SsapClientFindServiceRes *SsapClientFindServiceRes::Unmarshalling(Parcel &parcel)
{
    SsapClientFindServiceRes *result = new SsapClientFindServiceRes();
    if (result != nullptr && !result->ReadFromParcel(parcel)) {
        delete result;
        result = nullptr;
    }
    return result;
}

bool SsapClientFindServiceRes::ReadFromParcel(Parcel &parcel)
{
    if (!parcel.ReadUint16(startHandle_)) {
        return false;
    }
    if (!parcel.ReadUint16(endHandle_)) {
        return false;
    }
    std::shared_ptr<Uuid> uuid(parcel.ReadParcelable<Uuid>());
    if (!uuid) {
        return false;
    }
    uuid_ = *uuid;
    return true;
}

void SsapClientFindServiceRes::ConvertToClientFindServiceRes(ClientFindServiceRes &value) const
{
    value.startHandle = startHandle_;
    value.endHandle = endHandle_;
    value.uuid = uuid_.ConvertToSleUuid();
}

// SsapClientFindPropertyRes
SsapClientFindPropertyRes::SsapClientFindPropertyRes(const ClientFindPropertyRes &result)
{
    handle_ = result.handle;
    operateIndication_ = result.operateIndication;
    Uuid uuid(result.uuid);
    uuid_ = uuid;
    descriptorsCount_ = result.descriptorsCount;

    if (descriptorsCount_ != 0) {
        descriptorsType_ = std::make_unique<uint8_t[]>(descriptorsCount_);
        descriptorsType_[0] = result.descriptorsType;
    } else {
        descriptorsType_ = nullptr;
        descriptorsCount_ = 0;
    }

    // if (result.descriptorsType != nullptr && descriptorsCount_ != 0) {
    //     descriptorsType_ = std::make_unique<uint8_t[]>(descriptorsCount_);
    //     (void)memcpy_s(descriptorsType_.get(), descriptorsCount_, result.descriptorsType, descriptorsCount_);
    // } else {
    //     descriptorsType_ = nullptr;
    //     descriptorsCount_ = 0;
    // }
}

bool SsapClientFindPropertyRes::Marshalling(Parcel &parcel) const
{
    if(!parcel.WriteUint16(handle_)) {
        return false;
    }
    if(!parcel.WriteUint32(operateIndication_)) {
        return false;
    }
    if (!parcel.WriteParcelable(&uuid_)) {
        return false;
    }
    if(!parcel.WriteUint8(descriptorsCount_)) {
        return false;
    }
    for (size_t i = 0; i < descriptorsCount_; i++) {
        if(!parcel.WriteUint8(descriptorsType_[i])) {
            return false;
        }
    }
    return true;
}

SsapClientFindPropertyRes *SsapClientFindPropertyRes::Unmarshalling(Parcel &parcel)
{
    SsapClientFindPropertyRes *result = new SsapClientFindPropertyRes();
    if (result != nullptr && !result->ReadFromParcel(parcel)) {
        delete result;
        result = nullptr;
    }
    return result;
}

bool SsapClientFindPropertyRes::ReadFromParcel(Parcel &parcel)
{
    if (!parcel.ReadUint16(handle_)) {
        return false;
    }
    if (!parcel.ReadUint32(operateIndication_)) {
        return false;
    }
    std::shared_ptr<Uuid> uuid(parcel.ReadParcelable<Uuid>());
    if (!uuid) {
        return false;
    }
    uuid_ = *uuid;

    if (!parcel.ReadUint8(descriptorsCount_)) {
        return false;
    }
    if (descriptorsCount_ != 0) {
        uint8_t descriptorsType[descriptorsCount_];
        for (size_t i = 0; i < descriptorsCount_; i++) {
            if (!parcel.ReadUint8(descriptorsType[i])) {
                return false;
            }
        }
        descriptorsType_ = std::make_unique<uint8_t[]>(descriptorsCount_);
        if (memcpy_s(descriptorsType_.get(), descriptorsCount_, descriptorsType, descriptorsCount_) != SLE_NO_ERROR) {
            return false;
        }
    }
    return true;
}

void SsapClientFindPropertyRes::ConvertToClientFindPropertyRes(ClientFindPropertyRes &value) const
{
    value.handle = handle_;
    value.operateIndication = (SsapOperateIndication)operateIndication_;
    value.uuid = uuid_.ConvertToSleUuid();
    value.descriptorsCount = descriptorsCount_;
    value.descriptorsType = (SsapPropertyDescriptorType)descriptorsType_[0];
}
} // SleStandard
} // NearLink
} // OHOS